package com.xiaoge.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoge.auth.security.jwt.JwtTokenUtil;
import com.xiaoge.response.Result;
import com.xiaoge.response.ResultCode;
import com.xiaoge.system.entity.Department;
import com.xiaoge.system.entity.Role;
import com.xiaoge.system.entity.User;
import com.xiaoge.system.entity.UserRole;
import com.xiaoge.system.enums.UserStatusEnum;
import com.xiaoge.system.enums.UserTypeEnum;
import com.xiaoge.system.mapper.DepartmentMapper;
import com.xiaoge.system.mapper.RoleMapper;
import com.xiaoge.system.mapper.UserMapper;
import com.xiaoge.system.mapper.UserRoleMapper;
import com.xiaoge.system.service.LoginLogService;
import com.xiaoge.system.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author xiaoge
 * @since 2021-02-02
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private DepartmentMapper departmentMapper;

    private PasswordEncoder passwordEncoder;

    @Autowired
    private LoginLogService loginLogService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private RoleMapper roleMapper;

    public UserServiceImpl(DepartmentMapper departmentMapper, PasswordEncoder passwordEncoder) {
        this.departmentMapper = departmentMapper;
        this.passwordEncoder = passwordEncoder;
    }

    /**
     * 分页查询用户
     *
     * @param page
     * @param wrapper
     * @return
     */
    @Override
    public IPage<User> findUserPage(Page<User> page, QueryWrapper<User> wrapper,Long roleId) {
        return this.baseMapper.findUserPage(page, wrapper,roleId);
    }

    /**
     * 登录之后返回token
     *
     * @param username
     * @param password
     * @param code
     * @param request
     * @return
     */
    @Override
    public Result login(String username, String password, String code, HttpServletRequest request) {
        String captcha = (String) request.getSession().getAttribute("captcha");
        if (ObjectUtils.isEmpty(code) || !captcha.equalsIgnoreCase(code)) {
            return Result.error().message("验证码输入错误，请重新输入！");
        }
        //登录
        if (null == userService.getAdminByUserName(username)) {
            return Result.error().message("用户名或密码错误");
        }
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (null == userDetails || !passwordEncoder.matches(password, userDetails.getPassword())) {
            return Result.error().message("用户名或密码错误");
        }
        if (!userDetails.isEnabled()) {
            return Result.error(ResultCode.USER_ACCOUNT_DISABLE);
        }
        //更新security登录用户对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails
                , null, userDetails.getAuthorities());
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        //设置security全局登陆用户
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        request.getServletContext().setAttribute("authenticationToken", SecurityContextHolder.getContext().getAuthentication());
        //生成token
        String token = jwtTokenUtil.generateToken(userDetails);
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);
        //添加登陆日志
        loginLogService.add(request);
        return Result.ok().data("tokenMap", tokenMap);
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    @Override
    public User getAdminByUserName(String username) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
    }

    /**
     * 分配角色
     *
     * @param id   用户id
     * @param rids 角色数组
     */
    @Override
    @Transactional
    public void assignRoles(Long id, Long[] rids) {
        //删除之前用户的所有角色
        User user = userMapper.selectById(id);
        if (user == null) {
            throw new Error("用户不存在");
        }
        QueryWrapper<UserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", id);
        //删除之前分配的
        userRoleMapper.delete(queryWrapper);
        //增加现在分配的
        if (rids.length > 0) {
            for (Long rid : rids) {
                Role role = roleMapper.selectById(rid);
                if (role == null) {
                    throw new Error("roleId=" + rid + ",该角色不存在");
                }
                //判断角色状态
                if (role.getStatus() == 0) {
                    throw new Error("roleName=" + role.getRoleName() + ",该角色已禁用");
                }
                UserRole userRole = new UserRole();
                userRole.setUserId(id);
                userRole.setRoleId(rid);
                userRoleMapper.insert(userRole);
            }
        }
        //清除该用户的菜单缓存
        redisTemplate.delete("menus_" + id);
    }

    /**
     * 删除用户
     * @param id
     */
    @Override
    public Result delUser(Long id) {
        QueryWrapper<Department>queryWrapper =new QueryWrapper<>();
        queryWrapper.eq("mgr_id",id);
        Integer count=departmentMapper.selectCount(queryWrapper);
        if (count!=0){
            return Result.error(ResultCode.USER_IS_DEPARTMENT_HEAD);
        }
        QueryWrapper<UserRole>wrapper =new QueryWrapper<>();
        wrapper.eq("user_id",id);
        Integer integer =userRoleMapper.selectCount(wrapper);
        if (integer!=0){
            return Result.error(ResultCode.USER_HAVE_ROLE);
        }
        userMapper.deleteById(id);
        userRoleMapper.delete(wrapper);
        return Result.ok();
    }

    /*
     * 添加用户
     * */
    @Override
    public Result addUser(User user) {
        //判断是否用户名相同
        String username = user.getUsername();
        //获取部门
        Long departmentId = user.getDepartmentId();

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);

        Integer count = this.baseMapper.selectCount(wrapper);

        if (count != 0) {
            return Result.error(ResultCode.USER_ACCOUNT_ALREADY_EXIST);
        }
        Department department = departmentMapper.selectById(departmentId);
        if (department == null) {
            return Result.error(ResultCode.DEPARTMENT_NOT_EXIST);
        }
        String salt = UUID.randomUUID().toString().substring(0, 32);
        user.setSalt(salt);
        //使用spring secur 自带的密码加密策略
        user.setPassword(passwordEncoder.encode(user.getPassword()));

        //使用mybatis-plus的自动设置创建时间和更新时间

        //设置用户类型
        user.setType(UserTypeEnum.SYSTEM_USER.getTypeCode());
        //设置状态
        user.setStatus(UserStatusEnum.AVAILABLE.getStatusCode());

        this.baseMapper.insert(user);
        return Result.ok();
    }

    /**
     * 查询所有用户
     *
     * @return
     */
    @Override
    public List<User> findAll() {
        return userMapper.getAllUser();
    }

    /**
     * 根据用户id查询角色列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<Role> getRoles(Long userId) {
        return roleMapper.getRoles(userId);
    }
}
